package com.dynaBlaster.game;

import android.util.Log;

import com.dynaBlaster.elements.Bomb;
import com.dynaBlaster.elements.Creature;
import com.dynaBlaster.elements.Hero;
import com.dynaBlaster.elements.MonsterGlut;
import com.dynaBlaster.elements.PumpkinGhost;
import com.dynaBlaster.actions.Action;
import com.dynaBlaster.core.Point;
import com.dynaBlaster.elements.Agent;
import com.dynaBlaster.players.Player;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Random;

/*
 * Mechanika gry.
 * 
 */
public class Game {
	HashMap<Integer, Agent> agents;
	
	HashMap<Integer, Player> players;
	
	public static String LOG_TAG = "Game";
	
	public Hero hero;
	
	private ArrayList<Creature> monsters;

	private ArrayList<Bomb> bombs;
	
	public Board board;
	
	public ArrayList<Bomb> getBombs() {
		return bombs;
	}
	
	public static final Random random = new Random();


	public void initNewGame(Point boardSize) {

		// TODO: to bedze bardziej dynamiczne
		Point heroIndex = new Point(1, 1);
		Point exitIndex = new Point(5, 5);
		
		hero = new Hero(this);
		board = new Board(boardSize, this);
		
		
		hero.setPos(new Point(1, 1).mul(GameConfig.TILE_SIZE));
	
		monsters = new ArrayList<Creature>();
		bombs = new ArrayList<Bomb>();
	
		board.initWalls();
		board.initRandomBoard(heroIndex, exitIndex, random);
	
		for (int i = 0; i < GameConfig.COUNT_1ST_LEVEL_CREATURES; i++) {
			if (!addEnemyToGame(new PumpkinGhost(this)))
				break;
		}
	
		for (int i = 0; i < GameConfig.COUNT_2ND_LEVEL_CREATURES; i++) {
			if (!addEnemyToGame(new MonsterGlut(this)))
				break;
		}
	


	}

	
	boolean addEnemyToGame(Creature c) {
		int safety_counter = 0;
		Point field;
		do {
			field = board.getRandomTileByTerrain(Terrain.FREE);
			safety_counter++;
			if (safety_counter > GameConfig.RANDOM_SAFETY_COUNTER)
				break;
		} while (field != null && (isCreatureOnField(field) || isInHeroStartPoints(field)));

		if (safety_counter > GameConfig.RANDOM_SAFETY_COUNTER || field == null) {
			Log.w(LOG_TAG, "addEnemyToGame: brak miejsca,losowanie przerwane ");
			return false;
		}
		c.setPos(board.getTileInd(field));
		monsters.add(c);
		return true;
	}

	

	boolean isCreatureOnField(Point field) {
		for (Creature c : monsters) {
			if (board.getTileInd(c.getPos()).equals(field))
				return true;
		}
		return false;
	}





	//boolean isInHeroStartPoints(Point field) {
	//	if (field.equals(new Point(HERO_START_X, HERO_START_Y))
	//			|| field.equals(new Point(HERO_START_X + 1, HERO_START_Y))
	//			|| field.equals(new Point(HERO_START_X, HERO_START_Y + 1)))
	//		return true;
	//	return false;
	//}
	
	
	public ArrayList<Agent> getAgentsAtInd(Point ind){
		// zwraca liste obiektow gry na polu
		ArrayList<Agent> es;
		
		for (Agent a: agents.values()) {	        
	        if (getTileInd(a.getPos()).eq(ind)) {
				es.add(a);
			}
	    }
		
		return es;
	}
	
	// akcja
	private boolean plantBomb(Hero hero) {
		// bombe mozna polozyc na polu na ktorym nie ma innej bomby
		
		if (!hero.canPlantBomb())
			return false;
		
		Point ind = board.getTileInd(hero.getPos());
		
		for (Agent a: getAgentsAtInd(ind)){
			if (a instanceof Bomb) {
				return false;
			}
		}		
		
		addAgent(
			new Bomb(this, System.currentTimeMillis(), hero, board.getTilePos(ind))
		);
		
		hero.setJustPlantedBomb(bomb);
		
	}
	
	private void updateGame() {

		ArrayList<Bomb> alive = new ArrayList<Bomb>();
		for (Bomb b : bombs) {
			b.updateState(System.currentTimeMillis());
			if (!b.isDead())
				alive.add(b);
		}

		this.bombs = alive;

		for (Creature c : monsters)
			c.move();

		// creatures kill
		// for(Creature c : monsters)
		// if (c.touchesCreature(mHero)){
		// setMode(GAME_LOST);
		// return;
		// }

		// bombs kill hero
		for (Bomb b : bombs)
			if (b.touchesCreature(mHero)) {
				setMode(GAME_LOST);
				return;
			}
		// bombs kill creatures

		for (Bomb b : bombs)
			for (Creature c : monsters)
				if (b.touchesCreature(c)) {
					c.kill();
				}

		ArrayList<Creature> aliveCreats = new ArrayList<Creature>();
		for (Creature c : monsters)
			if (c.isAlive())
				aliveCreats.add(c);

		this.monsters = aliveCreats;

		// button control
		if (upKeyPressed || downKeyPressed || leftKeyPressed || rightKeyPressed)
			mHero.move();
		// touch control
		if (isHeroMoving)
			mHero.move();

		// winning
		if (mHero.isOverPoint(BoardView.getAbsCoord(new Point(exitX, exitY)))) {
			setMode(GAME_WON);
		}

	}
	
	private boolean isInPlantbombArea(int x, int y) {
		return  (x>0)&&(x<GameConfig.PLANT_BOMB_SIZE)
		&& (y>mYTileCount*GameConfig.TILE_SIZE-GameConfig.PLANT_BOMB_SIZE)&&(y<mYTileCount*GameConfig.TILE_SIZE);
	}
	
	void addPlayer(Player p){
		players.put((Integer)p.id, p);
	}
	
	void addAgent(Agent a){
		agents.put((Integer)a.id, a);
	}
	
	Player getPlayer(int id){
		return players.get(id);
	}
	
	Agent getAgent(int id){
		return agents.get(id);
	}
	
	void applyAction(Action a){
		
	}
	
	void update(){
		
	}
	
	public boolean isFree(Point toCheck, boolean allowCreatures, boolean allowWalls) {

		Boolean tmp = board.isFree(toCheck, allowCreatures, allowWalls);
		if (tmp == false){
			return false;
		}
		return true;
		
		//    	
		// check bombs
		//for (Bomb b : bombs)
		//	if (b.isOverPoint(toCheck))
		//		if (b != bombToIgnore)
		//			return false;

		//		
		// // check creatures
		//			
		/*
		if (allowCreatures)
			return true;
		else {
			for (Agent c : agents) {
				if (c.isOverPoint(toCheck)) {
					return false;
				}
			}
			return true;
		}
		*/
		

	}	

}
